﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;

namespace Chromatics
{
    /// <summary>
    /// Class which provides game logic
    /// </summary>
    public class GameLogic
    {
        // Graph of current level
        private Graph graph;

        // Painted colors
        private List<Color> colors;

        // Difficulty of level
        private static Difficulty currentDifficulty;

        // number jf level
        private static int currentLevelNumber;

        /// <summary>
        /// Default constructor
        /// </summary>
        public GameLogic()
        {
            graph = null;
            colors = null;
        }

        public static Difficulty CurrentDifficulty
        {
            get
            {
                return currentDifficulty;
            }
            set
            {
                currentDifficulty = value;
            }
        }

        public static int CurrentLevelNumber
        {
            get
            {
                return currentLevelNumber;
            }

            set
            {
                currentLevelNumber = value;
            }
        }

        /// <summary>
        /// Sets current level
        /// </summary>
        public void SetLevel()
        {
            if (CheckLevel(currentLevelNumber, currentDifficulty) == LevelStatus.Closed)
            {
                throw new InvalidOperationException("Needed level is closed!");
            }
            graph = DataLoader.Instance.LoadGraph(currentLevelNumber, currentDifficulty);
            colors = new List<Color>();
            for (int i = 0; i < graph.Peaks.Count; ++i)
            {
                colors.Add(PalleteColors.Default);
            }
        }

        /// <summary>
        /// Property to get graph elements to visualize
        /// </summary>
        public GraphView GetGraph
        {
            get 
            {
                return new GraphView() { LevelNumber = currentLevelNumber, ChromaticNumber = graph.ChromaticNumber, Colors = colors, Edges = graph.Edges, Peaks = graph.Peaks };
            }
        }

        /// <summary>
        /// Sets current level to next level
        /// </summary>
        /// <param name="number">number of level to set</param>
        /// <param name="Difficulty">difficulty</param>
        public void NextLevel()
        {
            Difficulty nextCom = currentDifficulty;
            int nextLvl;
            if (currentLevelNumber == DataLoader.Instance.LevelsCount(currentDifficulty))
            {
                if (currentDifficulty == Difficulty.Easy)
                    nextCom = Difficulty.Medium;
                else if (currentDifficulty == Difficulty.Medium)
                    nextCom = Difficulty.Hard;
                else
                    throw new Exception("There are no next level!");
                nextLvl = 1;
            }
            else
            {
                nextLvl = currentLevelNumber+1;
            }
            if (CheckLevel(nextLvl, nextCom) == LevelStatus.Closed)
            {
                throw new InvalidOperationException("Needed level is closed!");
            }
            currentLevelNumber = nextLvl;
            currentDifficulty = nextCom;
            graph = DataLoader.Instance.LoadGraph(nextLvl, nextCom);
            colors = new List<Color>();
            for (int i = 0; i < graph.Peaks.Count; ++i)
            {
                colors.Add(PalleteColors.Default);
            }
        }

        public bool isNextLevelLocked()
        {
            Difficulty nextCom = currentDifficulty;
            int nextLvl;
            if (currentLevelNumber == DataLoader.Instance.LevelsCount(currentDifficulty))
            {
                if (currentDifficulty == Difficulty.Easy)
                    nextCom = Difficulty.Medium;
                else if (currentDifficulty == Difficulty.Medium)
                    nextCom = Difficulty.Hard;
                else
                    return true;
                    //throw new Exception("There are no next level!");
                nextLvl = 1;
            }
            else
            {
                nextLvl = currentLevelNumber + 1;
            }
            if (CheckLevel(nextLvl, nextCom) == LevelStatus.Closed)
                return true;
            else
                return false;
        }

        /// <summary>
        /// Reset current level
        /// </summary>
        public void ResetCurrentLevel()
        {
            colors = new List<Color>();
            for (int i = 0; i < graph.Peaks.Count; ++i)
            {
                colors.Add(PalleteColors.Default);
            }
        }

        /// <summary>
        /// Gets current status of level
        /// </summary>
        /// <param name="number">number of level</param>
        /// <param name="Difficulty">difficulty</param>
        /// <returns>Level status Open,Closed or Active</returns>
        public LevelStatus CheckLevel(int number, Difficulty difficulty)
        {
            Level levelInfo = DataLoader.Instance.LoadLevelInfo(number, difficulty);
            return levelInfo.Status;
        }

        public int GetStarsForCurrentLevel()
        {
            int toRet = 0;
            if (GameState != LevelState.Accepted)
                throw new Exception("Level not completed!");
            int currentColors = 0;
            if (colors.Count(a => a == PalleteColors.Azure) > 0)
                currentColors++;
            if (colors.Count(a => a == PalleteColors.Blue) > 0)
                currentColors++;
            if (colors.Count(a => a == PalleteColors.Green) > 0)
                currentColors++;
            if (colors.Count(a => a == PalleteColors.Orange) > 0)
                currentColors++;
            if (colors.Count(a => a == PalleteColors.Red) > 0)
                currentColors++;
            if (colors.Count(a => a == PalleteColors.Yellow) > 0)
                currentColors++;
            if (currentColors == graph.ChromaticNumber)
                toRet = 3;
            else if (currentColors == graph.ChromaticNumber + 1)
                toRet = 2;
            else if (currentColors == graph.ChromaticNumber + 2)
                toRet = 1;
            else
                toRet = 0;
            return toRet;
        }

        /// <summary>
        /// Sets status of level
        /// </summary>
        /// <param name="number">number of level</param>
        /// <param name="Difficulty">difficulty</param>
        /// <returns>Level status</returns>
        public void SetLevelStatus(int number, Difficulty difficulty, LevelStatus status)
        {
            Level curr = new Level() { Number = number, Difficulty = difficulty, Status = status};
            DataLoader.Instance.SaveLevelInfo(curr);
        }

        /// <summary>
        /// Gets status of current level
        /// </summary>
        public LevelStatus CheckCurrentLevel()
        {
            return CheckLevel(currentLevelNumber,currentDifficulty);
        }

        /// <summary>
        /// Sets status of current level
        /// </summary>
        public void SetCurrentLevelStatus(LevelStatus status)
        {
            SetLevelStatus(currentLevelNumber, currentDifficulty,status);
        }

        /// <summary>
        /// Gets current level state
        /// </summary>
        public LevelState GameState
        {
            get 
            {
                foreach (Edge ed in graph.Edges)
                {
                    if (colors[ed.Start] == colors[ed.Finish] && colors[ed.Finish] != PalleteColors.Default)
                    {
                        return LevelState.Error;
                    }
                }
                foreach (Color cl in colors)
                {
                    if (cl == PalleteColors.Default)
                    {
                        return LevelState.Ok;
                    }
                }
                return LevelState.Accepted;
            }
        }

        /// <summary>
        /// Get bad edges in graph
        /// </summary>
        /// <returns> edges both ends of wich has same color</returns>
        public List<Edge> GetErrorEdges()
        {
            List<Edge> toRet = new List<Edge>();
            foreach (Edge ed in graph.Edges)
            {
                if (colors[ed.Start] == colors[ed.Finish] && colors[ed.Finish] != PalleteColors.Default)
                    toRet.Add(ed);
            }
            return toRet;
        }

        /// <summary>
        /// Set color to peak
        /// </summary>
        /// <param name="peak">number of peak</param>
        /// <param name="color">color</param>
        /// <returns></returns>
        public LevelState SetPeakColor(int peak, Color color)
        {
            colors[peak] = color;
            return GameState;
        }

        /// <summary>
        /// Complete current level and save user progres
        /// </summary>
        public void CompleteCurrentLevel()
        {
            if (GameState != LevelState.Accepted)
                throw new Exception("Level not completed!");
            int currentColors = 0;
            if (colors.Count(a => a == PalleteColors.Azure) > 0)
                currentColors++;
            if (colors.Count(a => a == PalleteColors.Blue) > 0)
                currentColors++;
            if (colors.Count(a => a == PalleteColors.Green) > 0)
                currentColors++;
            if (colors.Count(a => a == PalleteColors.Orange) > 0)
                currentColors++;
            if (colors.Count(a => a == PalleteColors.Red) > 0)
                currentColors++;
            if (colors.Count(a => a == PalleteColors.Yellow) > 0)
                currentColors++;
            LevelStatus curr;
            if (currentColors == graph.ChromaticNumber)
                curr = LevelStatus.Star3;
            else if (currentColors == graph.ChromaticNumber + 1)
                curr = LevelStatus.Star2;
            else if (currentColors == graph.ChromaticNumber + 2)
                curr = LevelStatus.Star1;
            else
                curr = LevelStatus.Star0;
            Level has = DataLoader.Instance.LoadLevelInfo(currentLevelNumber, currentDifficulty);
            if (has.Status == LevelStatus.Star3)
                return;
            if ((has.Status == LevelStatus.Star1 && curr == LevelStatus.Star0) || (has.Status == LevelStatus.Star2 && (curr == LevelStatus.Star1 || curr == LevelStatus.Star0)))
                return;
            DataLoader.Instance.SaveLevelInfo(new Level() { Number = currentLevelNumber, Difficulty = currentDifficulty, Status = curr});
            DataLoader.Instance.RecalcLevelDependencies();
        }

    }
}
